﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Reflection;

namespace Seven.Web.Http
{
    public class HttpUploadModule : IHttpModule
    {
        public void Init(HttpApplication application)
        {
            application.BeginRequest += new EventHandler(this.Application_BeginRequest);
            application.EndRequest += new EventHandler(this.Application_EndRequest);
            application.Error += new EventHandler(this.Application_Error);
        }

        /// <summary>
        /// 请求开始，分割文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Application_BeginRequest(Object sender, EventArgs e)
        {
            HttpApplication app = sender as HttpApplication;

            // 如果是文件上传
            if (IsUploadRequest(app.Request))
            {
                // 返回 HTTP 请求正文已被读取的部分。
                HttpWorkerRequest request = GetWorkerRequest(app.Context);
                Encoding encoding = app.Context.Request.ContentEncoding;

                int bytesRead = 0; // 已读数据大小
                int read; // 当前读取的块的大小
                int count = 8192; // 分块大小
                byte[] buffer; // 保存所有上传的数据
                byte[] tempBuff = null;

                if (request != null)
                {
                    tempBuff = request.GetPreloadedEntityBody();
                }
                if (tempBuff != null)
                {
                    // 获取上传大小
                    // 
                    long length = long.Parse(request.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentLength));

                    buffer = new byte[length];
                    count = tempBuff.Length; // 分块大小

                    // 将已上传数据复制过去
                    Buffer.BlockCopy(tempBuff, 0, buffer, bytesRead, count);

                    // 开始记录已上传大小
                    bytesRead = tempBuff.Length;

                    // 循环分块读取，直到所有数据读取结束
                    while (request.IsClientConnected() && !request.IsEntireEntityBodyIsPreloaded() && bytesRead < length)
                    {
                        // 如果最后一块大小小于分块大小，则重新分块
                        if (bytesRead + count > length)
                        {
                            count = (int)(length - bytesRead);
                            tempBuff = new byte[count];
                        }

                        // 分块读取
                        read = request.ReadEntityBody(tempBuff, count);

                        // 复制已读数据块
                        Buffer.BlockCopy(tempBuff, 0, buffer, bytesRead, read);

                        // 记录已上传大小
                        bytesRead += read;

                    }
                    if (request.IsClientConnected() && !request.IsEntireEntityBodyIsPreloaded())
                    {
                        // 传入已上传完的数据
                        InjectTextParts(request, buffer);

                        // 表示上传已结束

                    }
                }
            }
        }

        /// 结束请求后移除进度信息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Application_EndRequest(Object sender, EventArgs e)
        {

        }

        /// <summary>
        /// 如果出错了设置进度信息中状态为“Error”
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Application_Error(Object sender, EventArgs e)
        {

        }

        HttpWorkerRequest GetWorkerRequest(HttpContext context)
        {
            IServiceProvider provider = (IServiceProvider)HttpContext.Current;
            return (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest));
        }

        /// <summary>
        /// 传入已上传完的数据
        /// </summary>
        /// <param name="request"></param>
        /// <param name="textParts"></param>
        void InjectTextParts(HttpWorkerRequest request, byte[] textParts)
        {
            BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;

            Type type = request.GetType();

            while ((type != null) && (type.FullName != "System.Web.Hosting.ISAPIWorkerRequest"))
            {
                type = type.BaseType;
            }

            if (type != null)
            {
                type.GetField("_contentAvailLength", bindingFlags).SetValue(request, textParts.Length);
                type.GetField("_contentTotalLength", bindingFlags).SetValue(request, textParts.Length);
                type.GetField("_preloadedContent", bindingFlags).SetValue(request, textParts);
                type.GetField("_preloadedContentRead", bindingFlags).SetValue(request, true);
            }
        }

        /// <summary>
        /// 是否为附件上传
        /// 判断的根据是ContentType中有无multipart/form-data
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        bool IsUploadRequest(HttpRequest request)
        {
            return request.ContentType.ToLower() == "multipart/form-data";
        }

        public void Dispose()
        {
        }
    }

    public class UploadProcess
    {
        public long SaveAs(string fullSaveFilePath, string saveFilePath,HttpPostedFileBase file, out long fullLenth)
        {
            //本地文件长度
            long lStartPos = 0;
            //开始读取位置
            long startPosition = 0;
            //结束读取位置
            int endPosition = 0;
            fullLenth = 0;
            var contentRange = HttpContext.Current.Request.Headers["Content-Range"];
            //bytes 10000-19999/1157632
            if (!string.IsNullOrEmpty(contentRange))
            {
                contentRange = contentRange.Replace("bytes", "").Trim();
                int temp = contentRange.IndexOf("/");
                string length = contentRange.Substring(temp + 1);
                fullLenth = int.Parse(length);
                contentRange = contentRange.Substring(0, temp);

                string[] ranges = contentRange.Split('-');
                startPosition = int.Parse(ranges[0]);
                endPosition = int.Parse(ranges[1]);
            }
            System.IO.FileStream fs = null;

            try
            {
                if (System.IO.File.Exists(fullSaveFilePath))
                {
                    fs = System.IO.File.OpenWrite(fullSaveFilePath);
                    lStartPos = fs.Length;

                }
                else
                {
                    //if (startPosition == 0 && !System.IO.Directory.Exists(saveFilePath))
                    //{
                    //    System.IO.Directory.CreateDirectory(saveFilePath);
                    //}
                    fs = new System.IO.FileStream(fullSaveFilePath, System.IO.FileMode.Create);
                    lStartPos = 0;
                }
                if (lStartPos > endPosition)
                {
                    fs.Close();
                    //返回当前文件大小，通知浏览器从此位置开始上传
                    return lStartPos;
                }
                else if (lStartPos < startPosition)
                {
                    lStartPos = startPosition;
                }
                else if (lStartPos > startPosition && lStartPos < endPosition)
                {
                    lStartPos = startPosition;
                }
                fs.Seek(lStartPos, System.IO.SeekOrigin.Current);
                byte[] nbytes = new byte[1024];
                int nReadSize = 0;
                nReadSize = file.InputStream.Read(nbytes, 0, nbytes.Length);
                while (nReadSize > 0)
                {
                    fs.Write(nbytes, 0, nReadSize);
                    nReadSize = file.InputStream.Read(nbytes, 0, nReadSize);
                }

                fs.Close();
            }
            catch (Exception ex)
            {
                if (fs != null)
                {
                    fs.Close();
                }
            }

            return endPosition;
        }
    }
}
